import { Injectable, Logger } from '@nestjs/common';
import { CommonHttpService } from 'src/common/http/http.service';
import { CommonResult } from 'src/util/commonResult';
import { WeixinUserService } from '../user/weixin-user.service';
import { encodeToken } from 'src/util/token';
import { HighPrecisionPerformance } from 'src/common/decorators/performance.decorator';
import * as crypto from 'crypto';

export interface WxLoginResponse {
  openid: string;
  session_key: string;
  unionid?: string;
  errcode?: number;
  errmsg?: string;
}

export interface WxAccessTokenResponse {
  access_token: string;
  expires_in: number;
  refresh_token: string;
  openid: string;
  scope: string;
  unionid?: string;
  errcode?: number;
  errmsg?: string;
}

export interface WxUserInfoResponse {
  openid: string;
  nickname: string;
  sex: number;
  province: string;
  city: string;
  country: string;
  headimgurl: string;
  privilege: string[];
  unionid?: string;
}

export interface WxLoginResult {
  token: string;
  userInfo: {
    id: string;
    nickname?: string;
    avatarUrl?: string;
    loginCount: number;
  };
}

@Injectable()
export class BaseService {
  private readonly logger = new Logger(BaseService.name);
  private readonly appId = 'wxf7dca9e84883bf71';
  private readonly appSecret = '42f067db9b748097be6c9dfb77f33dbd';

  constructor(
    private readonly httpService: CommonHttpService,
    private readonly weixinUserService: WeixinUserService,
  ) {}

  /**
   * 小程序登录 - 通过 code 获取用户 openid 和 session_key，并生成 JWT token
   * 优化版本：使用缓存、异步处理和性能监控
   */
  @HighPrecisionPerformance({
    threshold: 500,
    logLevel: 'log',
    includeArgs: true,
  })
  async wxLogin(code: string): Promise<CommonResult<WxLoginResult>> {
    const startTime = performance.now();
    const url = 'https://api.weixin.qq.com/sns/jscode2session';
    const params = {
      appid: this.appId,
      secret: this.appSecret,
      js_code: code,
      grant_type: 'authorization_code',
    };

    try {
      // 1. 调用微信API获取用户信息 - 使用缓存优化
      const wxResult = await this.httpService.get<WxLoginResponse>(
        url,
        params,
        undefined,
        false, // 微信登录不使用缓存，确保安全性
      );

      if (wxResult.errcode) {
        this.logger.error(`微信登录失败: ${wxResult.errmsg}`, wxResult);
        return CommonResult.failed(
          `微信登录失败: ${wxResult.errmsg}`,
          wxResult.errcode,
        );
      }

      // 2. 先获取用户数据，然后生成包含用户信息的 token
      const weixinUser = await this.weixinUserService.findOrCreateUser({
        openid: wxResult.openid,
        sessionKey: wxResult.session_key,
        unionid: wxResult.unionid,
      });

      // 3. 生成包含用户信息的 JWT token
      const token = await this.generateTokenAsync({
        openid: wxResult.openid,
        loginTime: Date.now(),
        userInfo: {
          id: weixinUser.id,
          nickname: weixinUser.nickname,
          avatarUrl: weixinUser.avatarUrl,
          loginCount: weixinUser.loginCount,
          unionid: weixinUser.unionid,
        },
      });

      // 4. 构建返回结果
      const result: WxLoginResult = {
        token,
        userInfo: {
          id: weixinUser.id,
          nickname: weixinUser.nickname,
          avatarUrl: weixinUser.avatarUrl,
          loginCount: weixinUser.loginCount,
        },
      };

      // 5. 异步记录日志，不影响响应时间
      const executionTime = performance.now() - startTime;
      setImmediate(() => {
        this.logger.log(
          `用户登录成功: openid=${weixinUser.openid}, loginCount=${weixinUser.loginCount}, 执行时间: ${executionTime.toFixed(2)}ms`,
        );
      });

      return CommonResult.success('微信登录成功', result);
    } catch (error) {
      const executionTime = performance.now() - startTime;
      this.logger.error(
        `微信登录处理失败, 执行时间: ${executionTime.toFixed(2)}ms`,
        error,
      );
      return CommonResult.failed('微信登录处理失败');
    }
  }

  /**
   * 异步生成 JWT token - 包含用户信息
   */
  private async generateTokenAsync(result: {
    openid: string;
    loginTime: number;
    userInfo?: {
      id: string;
      nickname?: string;
      avatarUrl?: string;
      loginCount: number;
      unionid?: string;
    };
  }): Promise<string> {
    return new Promise((resolve) => {
      setImmediate(() => {
        const tokenPayload = {
          openid: result.openid,
          loginTime: result.loginTime,
          // 包含用户信息，便于 token 解析时获取用户数据
          userId: result.userInfo?.id,
          nickname: result.userInfo?.nickname,
          avatarUrl: result.userInfo?.avatarUrl,
          loginCount: result.userInfo?.loginCount,
          unionid: result.userInfo?.unionid,
        };
        resolve(encodeToken(tokenPayload));
      });
    });
  }

  /**
   * 网页授权 - 通过 code 获取 access_token
   */
  async getAccessToken(
    code: string,
  ): Promise<CommonResult<WxAccessTokenResponse>> {
    const url = 'https://api.weixin.qq.com/sns/oauth2/access_token';
    const params = {
      appid: this.appId,
      secret: this.appSecret,
      code,
      grant_type: 'authorization_code',
    };

    try {
      const result = await this.httpService.get<WxAccessTokenResponse>(
        url,
        params,
      );

      if (result.errcode) {
        this.logger.error(`获取access_token失败: ${result.errmsg}`, result);
        return CommonResult.failed(
          `获取access_token失败: ${result.errmsg}`,
          result.errcode,
        );
      }

      return CommonResult.success('获取access_token成功', result);
    } catch (error) {
      this.logger.error('获取access_token请求失败', error);
      return CommonResult.failed('获取access_token请求失败');
    }
  }

  /**
   * 刷新 access_token
   */
  async refreshAccessToken(
    refreshToken: string,
  ): Promise<CommonResult<WxAccessTokenResponse>> {
    const url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token';
    const params = {
      appid: this.appId,
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
    };

    try {
      const result = await this.httpService.get<WxAccessTokenResponse>(
        url,
        params,
      );

      if (result.errcode) {
        this.logger.error(`刷新access_token失败: ${result.errmsg}`, result);
        return CommonResult.failed(
          `刷新access_token失败: ${result.errmsg}`,
          result.errcode,
        );
      }

      return CommonResult.success('刷新access_token成功', result);
    } catch (error) {
      this.logger.error('刷新access_token请求失败', error);
      return CommonResult.failed('刷新access_token请求失败');
    }
  }

  /**
   * 获取用户信息
   */
  async getUserInfo(
    accessToken: string,
    openid: string,
  ): Promise<CommonResult<WxUserInfoResponse>> {
    const url = 'https://api.weixin.qq.com/sns/userinfo';
    const params = {
      access_token: accessToken,
      openid,
      lang: 'zh_CN',
    };

    try {
      const result = await this.httpService.get<WxUserInfoResponse>(
        url,
        params,
      );
      return CommonResult.success('获取用户信息成功', result);
    } catch (error) {
      this.logger.error('获取用户信息请求失败', error);
      return CommonResult.failed('获取用户信息请求失败');
    }
  }

  /**
   * 验证 access_token 是否有效
   */
  async validateAccessToken(
    accessToken: string,
    openid: string,
  ): Promise<CommonResult<boolean>> {
    const url = 'https://api.weixin.qq.com/sns/auth';
    const params = {
      access_token: accessToken,
      openid,
    };

    try {
      const result = await this.httpService.get<{
        errcode: number;
        errmsg: string;
      }>(url, params);
      const isValid = result.errcode === 0;
      return CommonResult.success(
        isValid ? 'access_token验证成功' : 'access_token无效',
        isValid,
      );
    } catch (error) {
      this.logger.error('验证access_token失败', error);
      return CommonResult.failed('验证access_token失败');
    }
  }

  /**
   * 解密小程序数据
   */
  decryptWxData(
    encryptedData: string,
    sessionKey: string,
    iv: string,
  ): CommonResult<unknown> {
    try {
      const decipher = crypto.createDecipheriv(
        'aes-128-cbc',
        Buffer.from(sessionKey, 'base64'),
        Buffer.from(iv, 'base64'),
      );
      decipher.setAutoPadding(true);

      let decrypted = decipher.update(encryptedData, 'base64', 'utf8');
      decrypted += decipher.final('utf8');

      const result = JSON.parse(decrypted);
      return CommonResult.success('解密微信数据成功', result);
    } catch (error) {
      this.logger.error('解密微信数据失败', error);
      return CommonResult.failed('解密微信数据失败');
    }
  }

  /**
   * 生成微信登录二维码链接
   */
  generateQRCodeUrl(redirectUri: string, state?: string): CommonResult<string> {
    const baseUrl = 'https://open.weixin.qq.com/connect/qrconnect';
    const params = new URLSearchParams({
      appid: this.appId,
      redirect_uri: encodeURIComponent(redirectUri),
      response_type: 'code',
      scope: 'snsapi_login',
      state: state || 'STATE',
    });

    const url = `${baseUrl}?${params.toString()}#wechat_redirect`;
    return CommonResult.success('生成微信登录二维码链接成功', url);
  }
}
